package utils

import (
	"fmt"
	"sync/atomic"
	"time"
)

/*
**
 */
type Workers struct {
	closeflag  int32
	configflag int32
	worker_n   int32
	worker_max int
	worker_min int
	lastIdleT  time.Time
	OnWork     func() bool
}

func NewWorkers() *Workers {
	rval := &Workers{
		worker_min: 1,
		worker_max: 10,
	}
	return rval
}

func (this *Workers) innerConfig(fn func()) {
	go func() {
		if atomic.CompareAndSwapInt32(&this.configflag, 0, 1) {
			fn()
			this.configflag = 0
		}
	}()
}

/*
**

	检测是否需要增加工作者
*/
func (this *Workers) CheckGrow() {
	if this.worker_n >= int32(this.worker_max) {
		return
	}
	if time.Since(this.lastIdleT).Seconds() > 5 { // 5秒没有空闲
		go this.innerDoWork()
	}
}

func (this *Workers) Close() {
	this.closeflag = 1
}

func (this *Workers) innerDoWork() {
	atomic.AddInt32(&this.worker_n, 1)
	defer func() {
		atomic.AddInt32(&this.worker_n, -1)
	}()

	idlecnt := 0
	check_free_cnt := 0

	for {
		if this.closeflag == 1 {
			break
		}

		workfn := this.OnWork
		if workfn != nil {
			if !workfn() {
				idlecnt++
				if idlecnt > 10 {
					time.Sleep(time.Millisecond * 100)
				} else {
					time.Sleep(time.Millisecond)
				}

				if this.worker_n > int32(this.worker_min) { // 空闲时 缩减工作者
					check_free_cnt++
					if check_free_cnt >= 2 { // 两次空闲后
						break
					}
					time.Sleep(time.Millisecond * 100)
				}
				this.lastIdleT = time.Now()
			} else {
				idlecnt = 0
			}
		} else {
			time.Sleep(time.Millisecond * 100)
		}
	}
}

func (this *Workers) StatusString() string {
	return fmt.Sprintf("worker:%d|%d|%d", this.worker_min, this.worker_n, this.worker_max)
}

func (this *Workers) CheckStart() {
	this.closeflag = 0
	this.innerConfig(func() {
		for {
			if this.closeflag == 1 {
				break
			}

			if this.worker_n < int32(this.worker_min) { // 启动最小的工作线程
				go this.innerDoWork()
				time.Sleep(time.Millisecond)
			} else {
				break
			}
		}
	})
}

func (this *Workers) ConfigMax(v int) {
	this.worker_max = v

	if this.worker_max < this.worker_min {
		this.worker_min = this.worker_max
	}
}

func (this *Workers) ConfigMin(v int) {
	this.worker_min = v
	if this.worker_max < this.worker_min {
		this.worker_max = this.worker_min
	}
}

func (this *Workers) WorkMax() int {
	return this.worker_max
}

func (this *Workers) WorkNum() int {
	return int(this.worker_n)
}
